/*--------------------------------------------------------------------------*\

  MAIN.C                1995 AVM

  This demo program shows how to use the CAPI 2.0 Development Kit.
  When the program is started, it prompts for a number which will be
  called from the CONNECT routine. After that there is the main loop where
  the program handles CAPI and keystrokes.
  Following is a list of available keys:
  'l'   Listen (CIP mask = 0x1FFF03FF) every service will be indicated
  'L'   Listen (CIP mask = 0x00000000) no incoming call will be indicated
    Listen is sent to all available controllers
  'c'   Connect to specified number on slot 0
  'C'   Connect to specified number on slot 1
  'd'   Disconnect slot 0
  'D'   Disconnect slot 1
  's'   Send datablock with size "SendBlockSize" on slot 0
  'S'   Send datablock with size "SendBlockSize" on slot 1
  'f'   Transfer a file on slot 0
  'F'   Transfer a file on slot 1
  'v'   Receive a file on slot 0
  'V'   Receive a file on slot 1
  'a'   Accept incoming call on slot 0
  'A'   Accept incoming call on slot 1
  'i'   Ignore incoming call on slot 0
  'I'   Ignore incoming call on slot 1
  'r'   Reject incoming call on slot 0
  'R'   Reject incoming call on slot 1

  Next is an example how to connect the local 2 B-channels:
  !! This will cost the same as one telephone call !!
  After the start press 'l' so that every incoming call will be indicated.
  Press 'c' and the program asks for a number to call, then dials the number.
  There should be an incoming call indication on slot 1. Press 'A' and the
  program answers the call on the second slot. Now everytime you send data
  with 's' or 'S' there must be an data indication on the opposite slot.
  Disconnect the slot with 'd' or 'D'

\*--------------------------------------------------------------------------*/
#if !defined (NDEBUG)
#define DEBUG
#define CPROT
#endif

#include "os.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <assert.h>

#include "c20lib\source\capi20.h"
#include "c20msg.h"
#include "capi.h"
#include "connect.h"
#include "contr.h"
#include "data.h"
#include "id.h"
#include "init.h"

/*--------------------------------------------------------------------------*\
\*--------------------------------------------------------------------------*/
static  char  testblock[2048];

/*----- note: you may enter your own number here, but if you -----*/
/*-----     supply a wrong number, some PBXs may reject the  -----*/
/*-----     CAPI messages containing the wrong number -----*/
/*----- e.g.: static  char    *CallingPartyNumber = "1234567"; -----*/
static  char  *CallingPartyNumber = NULL;

static  char  CalledPartyNumberArr[40];

#ifdef DEBUG
static char CAPI_PROT_BUF[CAPI_PROTOCOL_INIT_BUF_SIZE];
static char ProtocolFileName[80];
static FILE *ProtocolFile;
#endif

#define INVALID_SLOT  -1
#define maxSlots  2 /*----- this demo program handles max. -----*/
        /*----- two connections -----*/
static  ConnectionID  Slot[maxSlots];


#define B1PROTOCOL    0
#define B2PROTOCOL    0
#define B3PROTOCOL    0
#define B3CONFIGURATION   NULL


#define QueueSize 8

typedef struct __DataElement {
  char    DATA[SendBlockSize];
  unsigned short  DATA_LENGTH;
  unsigned    SENT;
} _DataElement;

typedef struct  __DataQueue {
  _DataElement  Element[QueueSize];
  unsigned    Head;
  unsigned    Tail;
  unsigned    Fill;
} _DataQueue;

_DataQueue    Queue;

static unsigned FileTransfer = FALSE; /*----- signals if filetransfer is in progress -----*/
static unsigned FileReceive  = FALSE; /*----- signals if filetransfer is in progress -----*/
static FILE *File;

/*--------------------------------------------------------------------------*\
 * Press_Key:
\*--------------------------------------------------------------------------*/
int Press_Key(void) {
  int c;

  if ((c = getch()) == 0)
  c = getch()+256;
  return c;
}

/*--------------------------------------------------------------------------*\
 * GetSlot: returns the slotnumber of the ConnectionID or INVALID_SLOT
\*--------------------------------------------------------------------------*/
int GetSlot(ConnectionID Con) {
  int   x;

  for (x=0; x<maxSlots; x++)
  if (Slot[x] == Con) return x;
  return INVALID_SLOT;
}

/*--------------------------------------------------------------------------*\
 * AllocSlot: allocates one slot, if none free returns INVALID_SLOT
\*--------------------------------------------------------------------------*/
int AllocSlot(ConnectionID Con) {
  int   x;

  for (x=0; x<maxSlots; x++)
  if (Slot[x] == INVALID_CONNECTION_ID) {
    Slot[x] = Con;
    return x;
  }
  return INVALID_SLOT;
}

/*--------------------------------------------------------------------------*\
 * FreeSlot: clear one slot
\*--------------------------------------------------------------------------*/
void FreeSlot(int index) {
  Slot[index] = INVALID_CONNECTION_ID;
}

/*--------------------------------------------------------------------------*\
 * MainDataAvailable: signals received data blocks
 * This function is called after a DATA_B3_INDication is received. The flag
 * DiscardData tells CAPI to free the memora area directly after the return
 * of this function when set to TRUE (1) which is the preset. When the flag
 * is set to FALSE (0) the data area MUST be freed later with ReleaseData.
 * The datahandle identifies the memory area. When reaching 7 unconfirmed
 * blocks, no more incoming data will be signaled until freeing at least
 * one block.
\*--------------------------------------------------------------------------*/
void MainDataAvailable(ConnectionID    Connection,
         void __far    *Data,
         unsigned short  DataLength,
         unsigned short  DataHandle,
         int       *DiscardData) {

  assert (Connection != INVALID_CONNECTION_ID);


# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** incoming data, slot %d ID %d, size %d , handle %u *****\n",
           GetSlot(Connection), Connection, DataLength, DataHandle);
# endif

  if ((FileReceive) && (File != NULL)) {
  fwrite(Data, 1, DataLength, File);
  }
  *DiscardData = TRUE;
}

/*--------------------------------------------------------------------------*\
 * MainDataConf: signals the successful sending of a datablock
 * This function is called after receiving a DATA_B3_CONFirmation. CAPI signals
 * that the datablock identified by DataHandle has been sent and the memory
 * area may be freed. The DataHandle is the same as specified in SendBlock.
\*--------------------------------------------------------------------------*/
void MainDataConf(ConnectionID    Connection,
      unsigned short  DataHandle,
      unsigned short  Info) {

  assert (Connection != INVALID_CONNECTION_ID);


  if (Info != 0) {
#   ifdef DEBUG
    CAPI_PROTOCOL_TEXT("***** datablock slot %d ID %d handle %d NOT sent , error: 0x%04X *****\n",
        GetSlot(Connection), Connection, DataHandle, Info);
#   endif
  return;
  }
  if (FileTransfer) {

  assert (DataHandle == (unsigned short)Queue.Tail);

  Queue.Element[Queue.Tail].SENT = FALSE;
  if (++Queue.Tail >= QueueSize) Queue.Tail = 0;
  Queue.Fill--;
  }
# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** datablock slot %d ID %d handle %d has been sent *****\n",
    GetSlot(Connection), Connection, DataHandle);
# endif
}

/*--------------------------------------------------------------------------*\
 * MainStateChange: signals a state change on both B-channels (connected,
 * disconnected). Whenever a channel changes his state this function is called
\*--------------------------------------------------------------------------*/
void MainStateChange(ConnectionID   Connection,
       ConnectionState  State) {
  int   index;

  assert (Connection != INVALID_CONNECTION_ID);


  index = GetSlot(Connection);
# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** state change slot %d ID %d: %s *****\n", index, Connection,
            ConnectionStateString[State]);
# endif
  if (State == Disconnected) {
  FreeSlot(index);
  }
}

/*--------------------------------------------------------------------------*\
 * MainIncomingCall: signals an incoming call
 * This function will be executed if a CONNECT_INDication appears to
 * inform the user.
\*--------------------------------------------------------------------------*/
void MainIncomingCall(ConnectionID  Connection,
        char    *CallingPartyNumber) {
  int   index;

  assert (Connection != INVALID_CONNECTION_ID);


# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** incoming call ,ID %d, caller: \"%s\" *****\n",Connection,CallingPartyNumber);
# endif
  index = AllocSlot(Connection);

  if (index == INVALID_SLOT) {
#   ifdef DEBUG
    CAPI_PROTOCOL_TEXT("***** no free slot available, rejecting call... *****\n");
#   endif
  AnswerCall(Connection, RejectValue_REJECT,0,0,0,NULL);
  return;
  }
# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** call assigned to slot %d *****\n", index);
# endif
}


#ifdef DEBUG

/*--------------------------------------------------------------------------*\
 * CAPI_PROT_HANDLE: This is a callback-function that has been specified
 * with CAPI_PROTOCOL_INIT. The first parameter is a pointer to the protocol-
 * message which is plain ASCII-text. The parameter t contains the type of
 * the message which can be CAPI_PROTOCOL_HEADER (appears only once when
 * calling CAPI_PROTOCOL_INIT), CAPI_PROTOCOL_MSG (the text contains a
 * decoded CAPI-message) and CAPI_PROTOCOL_TXT (the buffers contains a debug
 * message or a message sent with the function CAPI_PROTOCOL_TEXT).
 * If the type of the message is CAPI_PROTOCOL_MSG, the last parameter contains
 * a pointer to the decoded CAPI-message.
\*--------------------------------------------------------------------------*/
void CAPI_PROT_HANDLE(char     *Message,
        CAPI_PROTOCOL_TYP  t,
        CAPI_MESSAGE   m) {

  fprintf(ProtocolFile,"%s",Message);
  if (t != CAPI_PROTOCOL_MSG)
  puts(Message);

  if (t == CAPI_PROTOCOL_MSG) {
  _cmsg CMSG;

  CAPI_MESSAGE_2_CMSG(&CMSG, m);
  if ((FileTransfer || FileReceive) &&
    (CMSG.Command == CAPI_DATA_B3) && (CMSG.Info == 0) &&
    (CMSG.Reason == 0) && (CMSG.Reason_B3 == 0)) {

    return;
  }
  puts(Message);
  if (CMSG.Info != 0) {
    printf("Info 0x%04X: %s\n",CMSG.Info,Decode_Info(CMSG.Info));
    fprintf(ProtocolFile,"Info 0x%04X: %s\n",CMSG.Info,Decode_Info(CMSG.Info));
  }
  if (CMSG.Reason != 0) {
    printf("Reason 0x%04X: %s\n",CMSG.Reason,Decode_Info(CMSG.Reason));
    fprintf(ProtocolFile,"Reason 0x%04X: %s\n",CMSG.Reason,Decode_Info(CMSG.Reason));
  }
  if (CMSG.Reason_B3 != 0) {
    printf("Reason_B3 0x%04X: %s\n",CMSG.Reason_B3,Decode_Info(CMSG.Reason_B3));
    fprintf(ProtocolFile,"Reason_B3 0x%04X: %s\n",CMSG.Reason_B3,Decode_Info(CMSG.Reason_B3));
  }
  }
  fflush(ProtocolFile);
}

/*--------------------------------------------------------------------------*\
 * Prot_Init: Initialisation of the protocol
\*--------------------------------------------------------------------------*/
int Prot_Init(char *Filename) {
  char *p;

  strcpy(ProtocolFileName, Filename);
  p = strrchr(ProtocolFileName, '.');
  if (p) *p = '\0';
  strcat(ProtocolFileName, ".prt");

  if ((ProtocolFile=fopen(ProtocolFileName, "w"))==NULL) {
    printf("Can't open protocol-file !!\n");
  return FALSE;
  }
  CAPI_PROTOCOL_INIT(CAPI_PROT_BUF, CAPI_PROT_HANDLE);
  return TRUE;
}
#endif

/*--------------------------------------------------------------------------*\
 * The following _h functions are 'h'igh level functions for the ones
 * implemented in CONNECT.C . The _h functions perform some parameter tests
 * that would cause an assert on the low-level functions.
\*--------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------*\
 * Connect_h: Asks for a number to call then executes 'Connect'
\*--------------------------------------------------------------------------*/
unsigned Connect_h(ConnectionID      *Connection,
       char        *CallingPartyNumber,
       unsigned long     Service,
       unsigned short    B1Protocol,
       unsigned short    B2Protocol,
       unsigned short    B3Protocol,
       unsigned char __far *B3Configuration) {

  if (*Connection != INVALID_CONNECTION_ID) {
  printf("Connect_h: Connection is already in use\n");
  return 0xFFFF;
  }

  printf("Enter Number: ");
  fflush (stdout);
  gets(CalledPartyNumberArr);

  return Connect(Connection,
       CalledPartyNumberArr,
           CallingPartyNumber,
       Service,
       B1Protocol,
       B2Protocol,
       B3Protocol,
       B3Configuration);
}

/*--------------------------------------------------------------------------*\
 * Disconnect_h: high level Disconnect
\*--------------------------------------------------------------------------*/
unsigned Disconnect_h(ConnectionID Connection) {

  int     index;
  ConnectionState State;

  if (Connection == INVALID_CONNECTION_ID) {
  printf("Disconnect_h: ConnectionID is invalid\n");
  return 0xFFFF;
  }
  State = GetState(Connection);
  if ((State == Disconnected) || (State == D_DisconnectPending)) {
  index = GetSlot(Connection);
  printf("Disconnect_h: slot %d ID %d is disconnected\n",index, Connection);
  return 0xFFFF;
  }
  return Disconnect(Connection);
}

/*--------------------------------------------------------------------------*\
 * SendData_h: high level SendData
\*--------------------------------------------------------------------------*/
unsigned SendData_h(ConnectionID  Connection,
      void __far    *Data,
      unsigned short  DataLength,
      unsigned short  DataHandle) {

  int     index;
  ConnectionState State;

  if (Connection == INVALID_CONNECTION_ID) {
  printf("SendData_h: ConnectionID is invalid\n");
  return 0xFFFF;
  }
  State = GetState(Connection);
  if (State != Connected) {
  index = GetSlot(Connection);
  printf("SendData_h: slot %d ID %d is not connected\n",index, Connection);
  return 0xFFFF;
  }
  return SendData(Connection, Data, DataLength, DataHandle);
}

/*--------------------------------------------------------------------------*\
 * AnswerCall_h: high level AnswerCall
\*--------------------------------------------------------------------------*/
unsigned AnswerCall_h(ConnectionID    Connection,
        RejectValue   Reject,
        unsigned short    B1Protocol,
        unsigned short    B2Protocol,
        unsigned short    B3Protocol,
        unsigned char __far *B3Configuration) {

  int     index;
  ConnectionState State;

  if (Connection == INVALID_CONNECTION_ID) {
  printf("AnswerCall_h: ConnectionID is invalid\n");
  return 0xFFFF;
  }
  State = GetState(Connection);
  if (State != D_ConnectPending) {
  index = GetSlot(Connection);
  printf("AnswerCall_h: slot %d ID %d is the wrong state for answering\n",index, Connection);
  return 0xFFFF;
  }
  return AnswerCall(Connection,
        Reject,
        B1Protocol,
        B2Protocol,
        B3Protocol,
        B3Configuration);
}

/*--------------------------------------------------------------------------*\
 * InitQueue: resets the data queue
\*--------------------------------------------------------------------------*/
void InitQueue(void) {
  unsigned  x;

  for (x=0; x<QueueSize; x++) {
  Queue.Element[x].SENT  = FALSE;
  }
  Queue.Head = 0;
  Queue.Tail = 0;
  Queue.Fill = 0;
}

/*--------------------------------------------------------------------------*\
 * TransferData: sends datablocks from the queue to CAPI until a) all Blocks
 * from the queue are sent or b) an error occurs. This functions trys to send
 * the maximum of 7 unconfirmed datablocks to CAPI for maximum throughput.
\*--------------------------------------------------------------------------*/
void TransferData(int index) {
  MESSAGE_EXCHANGE_ERROR  error;
  unsigned      t;

  if (Queue.Fill > 0) {
  t = Queue.Tail;
  do {
    if (Queue.Element[t].SENT == FALSE) {
    error = SendData(index,
         (void __far *)Queue.Element[t].DATA,
         Queue.Element[t].DATA_LENGTH,
         (unsigned short)t);

    if (error != 0) {
      printf("Error transfering data: 0x%04X !!!",error);
      break;
    }
    Queue.Element[t].SENT = TRUE;
    }
    if (++t >= QueueSize) t = 0;
  } while (t != Queue.Head);
  }
}

/*--------------------------------------------------------------------------*\
 * SendFile: Sends a file
\*--------------------------------------------------------------------------*/
unsigned SendFile(int index) {

  char    Filename[80];
  unsigned    count;

  if (Slot[index] == INVALID_CONNECTION_ID) {
  printf("SendFile: ConnectionID is invalid\n");
  return 1;
  }
  if (GetState(Slot[index]) != Connected) {
  printf("SendFile: slot %d ID %d is not connected\n",index, Slot[index]);
  return 2;
  }
  printf("Enter Filename: ");
  fflush (stdout);
  gets(Filename);

  File = fopen(Filename, "rb");
  if (! File) {
#   ifdef DEBUG
    CAPI_PROTOCOL_TEXT("***** file not found *****\n");
#   endif
  return 3;
  }
  InitQueue();

  FileTransfer = TRUE;

# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** Starting datatransfer on slot %d, press any key to stop *****\n",index);
  CAPI_PROTOCOL_TEXT("***** there is no protocol output to the screen during transfer *****\n\n");
# endif
  do {

  if ((! feof(File)) && (Queue.Fill < 7)) {  /*----- max. 7 outstanding blocks supported by CAPI -----*/
    count = fread(&(Queue.Element[Queue.Head].DATA[0]), 1, SendBlockSize, File);
    if (count > 0) {
    Queue.Element[Queue.Head].DATA_LENGTH = (unsigned short)count;
    if (++Queue.Head >= QueueSize) Queue.Head = 0;
    Queue.Fill++;
    }
  }
  if (GetState(Slot[index]) != Connected) {
#     ifdef DEBUG
      CAPI_PROTOCOL_TEXT("***** connection broken *****\n");
#     endif
      break;
    }
    if (kbhit()) {
#     ifdef DEBUG
      CAPI_PROTOCOL_TEXT("***** interrupted by user *****\n");
#     endif
      break;
  }
  TransferData(index);
  Handle_CAPI_Msg();
  } while (Queue.Fill > 0);

  FileTransfer = FALSE;
# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** End of filetransfer *****\n");
# endif
  fclose(File);
  return 0;
}

/*--------------------------------------------------------------------------*\
 * ReceiveFile: Receives a file and writes it to disk
\*--------------------------------------------------------------------------*/
unsigned ReceiveFile(int index) {

  char    Filename[80];

  if (Slot[index] == INVALID_CONNECTION_ID) {
  printf("ReceiveFile: ConnectionID is invalid\n");
  return 1;
  }
  if (GetState(Slot[index]) != Connected) {
  printf("ReceiveFile: slot %d ID %d is not connected\n",index, Slot[index]);
  return 2;
  }
  printf("Enter Filename where incoming data shall be saved: ");
  fflush (stdout);
  gets(Filename);

  File = fopen(Filename, "wb");
  if (! File) {
#   ifdef DEBUG
    CAPI_PROTOCOL_TEXT("***** could not open file *****\n");
#   endif
  return 3;
  }
  InitQueue();

  FileReceive = TRUE;

# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** Waiting for data on slot %d, press any key to stop *****\n",index);
  CAPI_PROTOCOL_TEXT("***** there is no protocol output to the screen during transfer *****\n");
# endif
  do {
  if (GetState(Slot[index]) != Connected) {
#     ifdef DEBUG
      CAPI_PROTOCOL_TEXT("***** connection broken *****\n");
# endif
      break;
    }
  Handle_CAPI_Msg();
  } while (! kbhit());

  getch();
  FileReceive = FALSE;
# ifdef DEBUG
  CAPI_PROTOCOL_TEXT("***** End of filetransfer *****\n");
# endif
  fclose(File);
  return 0;
}

/*---------------------------------------------------------------------------*\
 * PrintHelp: tell the user the options
\*---------------------------------------------------------------------------*/
static void PrintHelp (void) {

  puts("\n\n");
  puts("'ESC'   Exit program");
  puts("'l'     Listen (CIP mask = 0x1FFF03FF) every service will be indicated");
  puts("'L'     Listen (CIP mask = 0x00000000) no incoming call will be indicated");
  puts("'c'+'C' Connect, the specified number will be called");
  puts("'d'     Disconnect slot 0");
  puts("'D'     Disconnect slot 1");
  puts("'s'     Send datablock with size \"SendBlockSize\" on slot 0");
  puts("'S'     Send datablock with size \"SendBlockSize\" on slot 1");
  puts("'f'     Transfer a file on slot 0");
  puts("'F'     Transfer a file on slot 1");
  puts("'v'     Receive a file on slot 0");
  puts("'V'     Receive a file on slot 1");
  puts("'a'     Accept incoming call on slot 0");
  puts("'A'     Accept incoming call on slot 1");
  puts("'i'     Ignore incoming call on slot 0");
  puts("'I'     Ignore incoming call on slot 1");
  puts("'r'     Reject incoming call on slot 0");
  puts("'R'     Reject incoming call on slot 1");
  puts("'?'     Print this help screen");
}

/*--------------------------------------------------------------------------*\
 * HandleKeyStroke: Checks the keyboard
\*--------------------------------------------------------------------------*/
int HandleKeyStroke(void) {
  int  i;

#if defined (TARGET_NW)
  delay(50);     // the netware NLM has to be cooperative
#endif
  if (kbhit()) {
  i = Press_Key();
  switch (i) {
    case 'q':
    case 27: {    /*----- ESCAPE -----*/
    printf("Exit program ?  y/n ");
        fflush (stdout);
    i = Press_Key();
    if ((i == 'y') || (i =='Y')) {
      puts("Y");
      return FALSE;
    }
    puts("N");
    return TRUE;
    }
    //case 'l':
        //Listen(ALL_SERVICES);
    //break;
    //case 'L':
    //    //Listen(NO_SERVICES);
    //break;
    case 'c':
    Connect_h(&Slot[0],
        CallingPartyNumber,
        DATA_TRANSFER,
        B1PROTOCOL,
        B2PROTOCOL,
        B3PROTOCOL,
        B3CONFIGURATION);
    break;
    case 'C':
    Connect_h(&Slot[1],
        CallingPartyNumber,
        DATA_TRANSFER,
        B1PROTOCOL,
        B2PROTOCOL,
        B3PROTOCOL,
        B3CONFIGURATION);
    break;
    case 'd':
    Disconnect_h(Slot[0]);
    break;
    case 'D':
    Disconnect_h(Slot[1]);
    break;
    case 's':
        SendData_h(Slot[0], (void __far *)&testblock, SendBlockSize, 1);
    break;
    case 'S':
        SendData_h(Slot[1], (void __far *)&testblock, SendBlockSize, 1);
    break;
    case 'f':
    SendFile(Slot[0]);
    break;
    case 'F':
    SendFile(Slot[1]);
    break;
    case 'v':
    ReceiveFile(Slot[0]);
    break;
    case 'V':
    ReceiveFile(Slot[1]);
    break;
    case 'a':
        AnswerCall_h(Slot[0],RejectValue_ACCEPT,B1PROTOCOL,B2PROTOCOL,B3PROTOCOL,NULL);
    break;
    case 'A':
        AnswerCall_h(Slot[1],RejectValue_ACCEPT,B1PROTOCOL,B2PROTOCOL,B3PROTOCOL,NULL);
    break;
    case 'i':
    AnswerCall_h(Slot[0],RejectValue_IGNORE,0,0,0,NULL);
    break;
    case 'I':
    AnswerCall_h(Slot[1],RejectValue_IGNORE,0,0,0,NULL);
    break;
    case 'r':
    AnswerCall_h(Slot[0],RejectValue_REJECT,0,0,0,NULL);
    break;
    case 'R':
    AnswerCall_h(Slot[1],RejectValue_REJECT,0,0,0,NULL);
    break;
      case 'h':
      case '?':
        PrintHelp();
    break;
  }
  }
  return TRUE;
}

/*--------------------------------------------------------------------------*\
 * Interact: main loop, checks keystrokes and CAPI-messages
\*--------------------------------------------------------------------------*/
void Interact(void) {
  int   numController;
  int   BChannels, Contr;


  numController = GetNumController ();
  BChannels = 0;
  for (Contr=1; Contr<=numController; Contr++)
  BChannels += GetNumOfSupportedBChannels(Contr);

  printf("Detected %i controllers with %i B-channels overall.\n",
              numController, BChannels);
  PrintHelp ();

  do {
  Handle_CAPI_Msg();
  } while (HandleKeyStroke());

  puts("\nProgram terminated\n");
}

/*--------------------------------------------------------------------------*\
 * Hangup: Disconnect both channels
\*--------------------------------------------------------------------------*/
void Hangup(void) {
  int i;


  if ((Slot[0] != INVALID_CONNECTION_ID) &&
    (GetState(Slot[0]) != Disconnected) &&
    (GetState(Slot[0]) != D_DisconnectPending))
  Disconnect(Slot[0]);

  if ((Slot[1] != INVALID_CONNECTION_ID) &&
    (GetState(Slot[1]) != Disconnected) &&
    (GetState(Slot[1]) != D_DisconnectPending))
  Disconnect(Slot[1]);

  do {
  Handle_CAPI_Msg();
  if (kbhit()) {
    while (kbhit()) {
    getch();
    }
    printf("Exit program ?  y/n ");
      fflush (stdout);
    i = Press_Key();
    if ((i == 'y') || (i =='Y')) {
    puts("Y");
    return;
    }
    puts("N");
  }
  }
  while ((Slot[0] != INVALID_CONNECTION_ID) || (Slot[1] != INVALID_CONNECTION_ID));
}

/*--------------------------------------------------------------------------*\
 * ctrlchandler: exits on CTRL-C and CTRL-BREAK
\*--------------------------------------------------------------------------*/
void ctrlchandler(int sig)
{
  signal( SIGINT, ctrlchandler );
  exit(0);
  sig = 0;  /*----- suppress warning -----*/
}

/*--------------------------------------------------------------------------*\
 * main: Init & exit functions
\*--------------------------------------------------------------------------*/

/*
#ifdef DEBUG
int main(int ac, char *av[]) {
#else
int main(void) {
#endif

  Slot[0] = INVALID_CONNECTION_ID;
  Slot[1] = INVALID_CONNECTION_ID;

  if (! RegisterCAPI ()) return 1;
  atexit (ReleaseCAPI);

  signal(SIGINT, ctrlchandler);

  InitConnectionIDHandling ();


#ifdef DEBUG
  if (! Prot_Init(av[ac-1])) return 2;
#endif

#ifdef __linux__
  init_tty();
  atexit (restore_tty);
#endif

  Interact();

  Hangup();

#ifdef DEBUG
  fclose(ProtocolFile);
#endif

  return 0;
}
   */